/*
===========================================================================

Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

#ifndef __P_SPEC__
#define __P_SPEC__


//
// End-level timer (-TIMER option)
//
extern	qboolean levelTimer;
extern	int	levelTimeCount;


//      Define values for map objects
#define MO_TELEPORTMAN          14


// at game start
void    P_InitPicAnims( void );

// at map load
void    P_SpawnSpecials( void );

// every tic
void    P_UpdateSpecials( void );

// when needed
qboolean
P_UseSpecialLine
( mobj_t*	thing,
  line_t*	line,
  int		side );

void
P_ShootSpecialLine
( mobj_t*	thing,
  line_t*	line );

void
P_CrossSpecialLine
( int		linenum,
  int		side,
  mobj_t*	thing );

void    P_PlayerInSpecialSector( player_t* player );

int
twoSided
( int		sector,
  int		line );

sector_t*
getSector
( int		currentSector,
  int		line,
  int		side );

side_t*
getSide
( int		currentSector,
  int		line,
  int		side );

fixed_t P_FindLowestFloorSurrounding( sector_t* sec );
fixed_t P_FindHighestFloorSurrounding( sector_t* sec );

fixed_t
P_FindNextHighestFloor
( sector_t*	sec,
  int		currentheight );

fixed_t P_FindLowestCeilingSurrounding( sector_t* sec );
fixed_t P_FindHighestCeilingSurrounding( sector_t* sec );

int
P_FindSectorFromLineTag
( line_t*	line,
  int		start );

int
P_FindMinSurroundingLight
( sector_t*	sector,
  int		max );

sector_t*
getNextSector
( line_t*	line,
  sector_t*	sec );


//
// SPECIAL
//
int EV_DoDonut( line_t* line );



//
// P_LIGHTS
//
typedef struct
{
	thinker_t	thinker;
	sector_t*	sector;
	int		count;
	int		maxlight;
	int		minlight;

} fireflicker_t;



typedef struct
{
	thinker_t	thinker;
	sector_t*	sector;
	int		count;
	int		maxlight;
	int		minlight;
	int		maxtime;
	int		mintime;

} lightflash_t;



typedef struct
{
	thinker_t	thinker;
	sector_t*	sector;
	int		count;
	int		minlight;
	int		maxlight;
	int		darktime;
	int		brighttime;

} strobe_t;




typedef struct
{
	thinker_t	thinker;
	sector_t*	sector;
	int		minlight;
	int		maxlight;
	int		direction;

} glow_t;


#define GLOWSPEED			8
#define STROBEBRIGHT		5
#define FASTDARK			15
#define SLOWDARK			35

void	T_FireFlicker( fireflicker_t* flick );
void    P_SpawnFireFlicker( sector_t* sector );
void    T_LightFlash( lightflash_t* flash );
void    P_SpawnLightFlash( sector_t* sector );
void    T_StrobeFlash( strobe_t* flash );

void
P_SpawnStrobeFlash
( sector_t*	sector,
  int		fastOrSlow,
  int		inSync );

void    EV_StartLightStrobing( line_t* line );
void    EV_TurnTagLightsOff( line_t* line );

void
EV_LightTurnOn
( line_t*	line,
  int		bright );

void    T_Glow( glow_t* g );
void    P_SpawnGlowingLight( sector_t* sector );




//
// P_SWITCH
//
typedef struct
{
	char	name1[9];
	char	name2[9];
	short	episode;

} switchlist_t;


typedef enum
{
	top,
	middle,
	bottom

} bwhere_e;


typedef struct
{
	line_t*	line;
	bwhere_e	where;
	int		btexture;
	int		btimer;
	union
	{
		mobj_t* 		soundorg;
		degenmobj_t* 	degensoundorg;
	};
} button_t;




// max # of wall switches in a level
#define MAXSWITCHES		50

// 4 players, 4 buttons each at once, max.
#define MAXBUTTONS		16

// 1 second, in ticks.
#define BUTTONTIME      TICRATE

extern button_t	buttonlist[MAXBUTTONS];

void
P_ChangeSwitchTexture
( line_t*	line,
  int		useAgain );

void P_InitSwitchList( void );


//
// P_PLATS
//
typedef enum
{
	up,
	down,
	waiting,
	in_stasis

} plat_e;



typedef enum
{
	perpetualRaise,
	downWaitUpStay,
	raiseAndChange,
	raiseToNearestAndChange,
	blazeDWUS

} plattype_e;



typedef struct
{
	thinker_t	thinker;
	sector_t*	sector;
	fixed_t	speed;
	fixed_t	low;
	fixed_t	high;
	int		wait;
	int		count;
	plat_e	status;
	plat_e	oldstatus;
	qboolean	crush;
	int		tag;
	plattype_e	type;

} plat_t;



#define PLATWAIT		3
#define PLATSPEED		FRACUNIT
#define MAXPLATS		30


extern plat_t*	activeplats[MAXPLATS];

void    T_PlatRaise( plat_t*	plat );

int
EV_DoPlat
( line_t*	line,
  plattype_e	type,
  int		amount );

void    P_AddActivePlat( plat_t* plat );
void    P_RemoveActivePlat( plat_t* plat );
void    EV_StopPlat( line_t* line );
void    P_ActivateInStasis( int tag );


//
// P_DOORS
//
typedef enum
{
	normal,
	close30ThenOpen,
	closed,
	opened,
	raiseIn5Mins,
	blazeRaise,
	blazeOpen,
	blazeClose

} vldoor_e;



typedef struct
{
	thinker_t	thinker;
	vldoor_e	type;
	sector_t*	sector;
	fixed_t	topheight;
	fixed_t	speed;

	// 1 = up, 0 = waiting at top, -1 = down
	int             direction;

	// tics to wait at the top
	int             topwait;
	// (keep in case a door going down is reset)
	// when it reaches 0, start going down
	int             topcountdown;

} vldoor_t;



#define VDOORSPEED		FRACUNIT*2
#define VDOORWAIT		150

void
EV_VerticalDoor
( line_t*	line,
  mobj_t*	thing );

int
EV_DoDoor
( line_t*	line,
  vldoor_e	type );

int
EV_DoLockedDoor
( line_t*	line,
  vldoor_e	type,
  mobj_t*	thing );

void    T_VerticalDoor( vldoor_t* door );
void    P_SpawnDoorCloseIn30( sector_t* sec );

void
P_SpawnDoorRaiseIn5Mins
( sector_t*	sec,
  int		secnum );



#if 0 // UNUSED
//
//      Sliding doors...
//
typedef enum
{
	sd_opening,
	sd_waiting,
	sd_closing

} sd_e;



typedef enum
{
	sdt_openOnly,
	sdt_closeOnly,
	sdt_openAndClose

} sdt_e;




typedef struct
{
	thinker_t	thinker;
	sdt_e	type;
	line_t*	line;
	int		frame;
	int		whichDoorIndex;
	int		timer;
	sector_t*	frontsector;
	sector_t*	backsector;
	sd_e	 status;

} slidedoor_t;



typedef struct
{
	char	frontFrame1[9];
	char	frontFrame2[9];
	char	frontFrame3[9];
	char	frontFrame4[9];
	char	backFrame1[9];
	char	backFrame2[9];
	char	backFrame3[9];
	char	backFrame4[9];

} slidename_t;



typedef struct
{
	int             frontFrames[4];
	int             backFrames[4];

} slideframe_t;



// how many frames of animation
#define SNUMFRAMES		4

#define SDOORWAIT		TICRATE*3
#define SWAITTICS		4

// how many diff. types of anims
#define MAXSLIDEDOORS	5

void P_InitSlidingDoorFrames( void );

void
EV_SlidingDoor
( line_t*	line,
  mobj_t*	thing );
#endif



//
// P_CEILNG
//
typedef enum
{
	lowerToFloor,
	raiseToHighest,
	lowerAndCrush,
	crushAndRaise,
	fastCrushAndRaise,
	silentCrushAndRaise

} ceiling_e;



typedef struct
{
	thinker_t	thinker;
	ceiling_e	type;
	sector_t*	sector;
	fixed_t	bottomheight;
	fixed_t	topheight;
	fixed_t	speed;
	qboolean	crush;

	// 1 = up, 0 = waiting, -1 = down
	int		direction;

	// ID
	int		tag;
	int		olddirection;

} ceiling_t;





#define CEILSPEED		FRACUNIT
#define CEILWAIT		150
#define MAXCEILINGS		30

extern ceiling_t*	activeceilings[MAXCEILINGS];

int
EV_DoCeiling
( line_t*	line,
  ceiling_e	type );

void    T_MoveCeiling( ceiling_t* ceiling );
void    P_AddActiveCeiling( ceiling_t* c );
void    P_RemoveActiveCeiling( ceiling_t* c );
int	EV_CeilingCrushStop( line_t* line );
void    P_ActivateInStasisCeiling( line_t* line );


//
// P_FLOOR
//
typedef enum
{
	// lower floor to highest surrounding floor
	lowerFloor,

	// lower floor to lowest surrounding floor
	lowerFloorToLowest,

	// lower floor to highest surrounding floor VERY FAST
	turboLower,

	// raise floor to lowest surrounding CEILING
	raiseFloor,

	// raise floor to next highest surrounding floor
	raiseFloorToNearest,

	// raise floor to shortest height texture around it
	raiseToTexture,

	// lower floor to lowest surrounding floor
	//  and change floorpic
	lowerAndChange,

	raiseFloor24,
	raiseFloor24AndChange,
	raiseFloorCrush,

	// raise to next highest floor, turbo-speed
	raiseFloorTurbo,
	donutRaise,
	raiseFloor512

} floor_e;




typedef enum
{
	build8,	// slowly build by 8
	turbo16	// quickly build by 16

} stair_e;



typedef struct
{
	thinker_t	thinker;
	floor_e	type;
	qboolean	crush;
	sector_t*	sector;
	int		direction;
	int		newspecial;
	short	texture;
	fixed_t	floordestheight;
	fixed_t	speed;

} floormove_t;



#define FLOORSPEED		FRACUNIT

typedef enum
{
	ok,
	crushed,
	pastdest

} result_e;

result_e
T_MovePlane
( sector_t*	sector,
  fixed_t	speed,
  fixed_t	dest,
  qboolean	crush,
  int		floorOrCeiling,
  int		direction );

int
EV_BuildStairs
( line_t*	line,
  stair_e	type );

int
EV_DoFloor
( line_t*	line,
  floor_e	floortype );

void T_MoveFloor( floormove_t* floor );

//
// P_TELEPT
//
int
EV_Teleport
( line_t*	line,
  int		side,
  mobj_t*	thing );

#endif

